/*
Dominique Jannone
Guillaume Marre
Yohan Ojeda
Laurent Schiavon
*/
package Econf_Audio;

import javax.media.*;
import javax.media.format.*;
import javax.media.protocol.*;
import javax.media.control.*;
import java.util.*;
import java.io.*;
import javax.media.rtp.*;

import java.net.InetAddress;
import javax.media.control.BufferControl;

import model.ConnexionDb;

import java.util.logging.Level;
import java.util.logging.Logger;



public class Emetteur_serveur {
	
	// log
		public static final Logger logger = Logger.getLogger(Emetteur_serveur.class.getName());

        private static int portE = 22220;
//		private static String ipClient = "147.171.79.85";
//		private static String ipClient2 = "147.171.79.67";
		private static RTPManager[] rtpm;
		private DataSource ds;
		private static int instance;
		private static int formatPriority2 = -1;
		private static int formatPriority1 = -1;
		private static int formatPriority3 = -1;
   
		public Emetteur_serveur(DataSource dataS, RTPManager[] rtpm2, int instance) {
			// TODO Auto-generated constructor stub
			ds = dataS;
			rtpm = rtpm2;
			this.instance = instance;
			
			
			initEmmetteur();
		}
	

		/**
         * @param args
         */
			
		
        public  void initEmmetteur() {
        	logger.log(Level.INFO,"Emmetteur serveur");
        	
                int                              i, j;
                int                              nCount=0;
              
                        
//                      Déclaration du processeur
                        Processor FichierCessor = null;
                        try{
                                // Check to see if there's a buffer control on the data source.
                                // It could be that we are using a capture data source.
                                Control c = (Control)ds.getControl("javax.media.control.BufferControl");
                                if (c != null){
                                        ((BufferControl)c).setBufferLength(1);
                                        ((BufferControl)c).setMinimumThreshold(2);
                                        ((BufferControl)c).setEnabledThreshold(true);

                                }
                                        FichierCessor = Manager.createProcessor(ds);
                                
                                //Appel des fonctions qui vont permettre le lancement du flux RTP
                                configure(FichierCessor);
                                SetSupportedFormat(FichierCessor);
                                //passer dans l'etat realized du processor
                                realize(FichierCessor);
                                //start  
                                Demarre(FichierCessor); 
                                launchRTPManager(FichierCessor);
                        }
                        catch(IOException e)
                        {
                        	logger.log(Level.SEVERE,e.getClass() + ": " +  e.getMessage(), e);
                        }
                        catch(NoProcessorException e)
                        {
                        	logger.log(Level.SEVERE,e.getClass() + ": " +  e.getMessage(), e);
                        }

        }
        public static Processor configure(Processor p)  
        {
                //Attendre tant que le Processor n'est pas configuré.
                while(p.getState() < Processor.Configured)
                {
                        //Configuration du Processor
                        p.configure();
                }
                return p;
        }
        public static void SetSupportedFormat(Processor p)
        {
                //On met la description du contenu de sortie à RAW_RTP
                ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW_RTP);
                p.setContentDescriptor(cd);
                
                //On obtient les différentes pistes du processor
                TrackControl track[] = p.getTrackControls();
                for(int i = 0; i < track.length; i++)
                {
                        //on obtient les formats supportés pour cette piste
                        Format suppFormats[] = track[i].getSupportedFormats();
                        //Si il y a au moins un format supporté
                        //System.out.println();
                        for ( int t=0; t < suppFormats.length;t++)
                        {
                        	logger.log(Level.INFO,"RTP supported format: "+suppFormats[t]);
                        	// ADD 
                            if (suppFormats[t].getEncoding().equals(AudioFormat.DVI_RTP)) formatPriority1 =t;
                            if (suppFormats[t].getEncoding().equals(AudioFormat.GSM_RTP)) formatPriority2 =t;
                            if (suppFormats[t].getEncoding().equals(AudioFormat.ULAW_RTP)) formatPriority3 =t;
                        }
                        if(suppFormats.length > 0)
                        {
                        	int formatUse;
                        	if (formatPriority1 != -1) formatUse = formatPriority1;
                        	else if (formatPriority2 != -1) formatUse = formatPriority2;
                        	else if (formatPriority3 != -1) formatUse = formatPriority3;
                        	else formatUse = suppFormats.length-1;
                        	
                        	track[i].setFormat(suppFormats[formatUse]);
                                logger.log(Level.INFO,"Track " + i +" est transmis as :"+suppFormats[formatUse]);
                                if (track[i].getFormat() instanceof AudioFormat) {
                                        int packetRate = 5;
                                        PacketSizeControl pktCtrl = (PacketSizeControl) p.getControl(PacketSizeControl.class.getName());
                                        if (pktCtrl != null) {
                                                try {
                                                         pktCtrl.setPacketSize(getPacketSize(track[i].getFormat(), packetRate));
                                                        //pktCtrl.setPacketSize(pktCtrl.getPacketSize());
                                                        //pktCtrl.setPacketSize(1);
                                                }
                                                catch (IllegalArgumentException e) {
                                                        pktCtrl.setPacketSize(80);
                                                        // Do nothing
                                                }
                                        }
                                }

                                
                                
                                
                        }
                        else
                        {
                                track[i].setEnabled(false);
                        }
                }
                
                
        }
        
        private static int getPacketSize(Format codecFormat, int milliseconds) throws IllegalArgumentException {
                String encoding = codecFormat.getEncoding();
                if (encoding.equalsIgnoreCase(AudioFormat.GSM) ||
                                encoding.equalsIgnoreCase(AudioFormat.GSM_RTP)) {
                        return milliseconds * 4; // 1 byte per millisec
                }
                else if (encoding.equalsIgnoreCase(AudioFormat.ULAW) ||
                                encoding.equalsIgnoreCase(AudioFormat.ULAW_RTP)) {
                        return milliseconds * 8;
                }
                else {
                        throw new IllegalArgumentException("Unknown codec type");
                }
        }

        
        public static Processor realize(Processor p)
        {
                //Attendre tant que le Processor n'est pas réalisé.
                while(p.getState() < Processor.Realized)
                {               
                        //Réalisation du Processor
                        p.realize();
                }
                return p;
        }
        
        public static void Demarre(Processor p)
        {
                //Demarrage du Processor
                p.start();
                logger.log(Level.INFO,"Processor started");
        }

        public static void launchRTPManager(Processor p)
        {
                //Creation du DataSource correspondant au Processor
                DataSource OutputSource = p.getDataOutput();
                PushBufferDataSource pbds = (PushBufferDataSource)OutputSource;
                PushBufferStream pbss[] = pbds.getStreams();                      
                //Nouvelle Instance d'un RTPManager       
//                RTPManager rtpm[] = new RTPManager[pbss.length];
                
                //System.out.println("taille:" +pbss.length);
                //RTPManager rtpm;
                logger.log(Level.INFO,"launchRTPManager");
                for(int i=0; i < pbss.length;i++)       
                {
                        try{
//                                rtpm[i] = RTPManager.newInstance();
                                //Création d'une SessionAddress 
//                                SessionAddress localaddr = new SessionAddress(InetAddress.getLocalHost(),9999);
                                //Initialisation du RTPManager 
//                                rtpm[i].initialize(localaddr);
                                //Création d'une SessionAddress 
//                                SessionAddress destaddr = new SessionAddress(InetAddress.getByName(ipClient ),portE);
//                                SessionAddress destaddr2 = new SessionAddress(InetAddress.getByName(ipClient2 ),portE);
                                
                                //Ajout de cette SessionAddress dans le RTPManager
//                                rtpm[i].addTarget(destaddr);
//                                rtpm[i].addTarget(destaddr2);
//                                System.err.println("Creation RTP session "+ipClient+" port : "+portE);                                    
                                //Creation d'un SendStream à partir du DataSource                               
                                SendStream ss2 = rtpm[instance].createSendStream(OutputSource,i);
                                //Demarrage du SendStream
                                ss2.start();
                                logger.log(Level.INFO,"Started ");
                        }
                        catch(Exception e)
                        {
                        	logger.log(Level.SEVERE,e.getClass() + ": " +  e.getMessage(), e);
                        }         
                        
                }       
        }
        
}
